package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.mapper.AlbumAttributeValueMapper;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.base.BaseEntity;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.order.client.OrderInfoFeignClient;
import com.atguigu.tingshu.query.album.AlbumInfoQuery;
import com.atguigu.tingshu.vo.album.AlbumAttributeValueVo;
import com.atguigu.tingshu.vo.album.AlbumInfoVo;
import com.atguigu.tingshu.vo.album.AlbumListVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.ReturnedMessage;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
@Transactional(rollbackFor = Exception.class)
public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService {

    @Autowired
    private AlbumAttributeValueMapper albumAttributeValueMapper;

    @Autowired
    private AlbumStatMapper albumStatMapper;

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

  @Autowired
  private OrderInfoFeignClient orderInfoFeignClient;

  @Autowired
  private TrackInfoMapper trackInfoMapper;

  /**
   * 订单支付成功后 回调此方法 增加购买次数
   * @param orderNo
   */
  @Override
  public void updateAlbumStat(String orderNo) {
    //查询订单的信息
    OrderInfo orderInfo = orderInfoFeignClient.getOrderInfo(orderNo);
    // 如果订单信息为空 或 订单的类型为VIP会员 直接结束方法
    if(orderInfo == null || orderInfo.getItemType().equals("1003")){
      return;
    }
    //获取专辑的id或者声音的id
    Long itemId = orderInfo.getOrderDetailList().get(0).getItemId();
    //初始化数量
    Integer num = 1;
    // 如果是声音 增加其所在的专辑的购买量
    if(orderInfo.getItemType().equals("1002")){
      //查询声音的详细信息
      TrackInfo trackInfo = trackInfoMapper.selectById(itemId);
      //获取其是其所在的专辑id
      itemId = trackInfo.getAlbumId();
      //次数
      num = orderInfo.getOrderDetailList().size();
    }
    //专辑统计数据修改
    albumStatMapper.updateStat(itemId, SystemConstant.ALBUM_STAT_BROWSE, num);
  }
    @Override
    public void saveAlbumInfo(AlbumInfoVo albumInfoVo) {
        Long userId = AuthContextHolder.getUserId();
        // 将vo转化为do
        AlbumInfo albumInfo = new AlbumInfo();
        // 属性转移
        BeanUtils.copyProperties(albumInfoVo, albumInfo);
        // 登录完成以后优化 补全数据
        albumInfo.setUserId(userId);
        albumInfo.setStatus("0301");
        albumInfo.setTracksForFree(5); // 免费5集
        // 保存专辑数据 album_Info
        boolean flag = this.save(albumInfo);
        if (!flag){
            throw new GuiguException(201, "新增专辑数据失败");
        }
        // 获取专辑Id
        Long albumId = albumInfo.getId(); // 新增后就可以获取Id mybatis实现的
        // 新增专辑的标签表数据
        // 遍历标签列表 逐条新增
        albumInfoVo.getAlbumAttributeValueVoList().stream().forEach(albumAttributeValueVo -> {
            AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
            BeanUtils.copyProperties(albumAttributeValueVo, albumAttributeValue);
            // 设置专辑的Id
            albumAttributeValue.setAlbumId(albumId);
            // 执行新增
            int row = albumAttributeValueMapper.insert(albumAttributeValue);
            if (row <= 0){
                throw new GuiguException(201,"新增专辑的标签数据失败");
            }
        });

        // 初始化专辑的统计表数据
        initAlbumStat(albumId);

        // 1105 判断专辑的状态是否为上架 上架则通知es同步数据 不上架不用操作
        if(albumInfo.getIsOpen().equals("1")){
            CorrelationData correlationData = new CorrelationData();
            correlationData.setReturned(new ReturnedMessage(
                    new Message(albumId.toString().getBytes()),
                    -1,
                    null,
                    null,
                    "album.es.upper"));
            //通知es写数据
            rabbitTemplate.convertAndSend("album_info_exchange",
                                          "album.es.upper",
                                          albumId + "",
                                          correlationData);
        }
    }

  /**
   * 查询当前用户的分页专辑列表
   *
   * @param albumInfoQuery
   * @return
   */
  @Override
  public IPage<AlbumListVo> findUserAlbumPage(
      Page<AlbumListVo> albumListVoPage, AlbumInfoQuery albumInfoQuery) {
        Long userId = AuthContextHolder.getUserId();
        // 设置用户Id
        albumInfoQuery.setUserId(userId);
        return albumInfoMapper.findUserAlbumPage(albumListVoPage, albumInfoQuery);
    }

    /**
     * 根据专辑Id删除专辑
     * @param albumId
     * @return
     */
    @Override
    public void removeAlbumInfo(Long albumId) {
        Long userId = AuthContextHolder.getUserId();
        // 删除专辑
        if(!remove(new LambdaQueryWrapper<AlbumInfo>()
                           .eq(AlbumInfo::getId, albumId)
                           .eq(AlbumInfo::getUserId, userId))){
            throw new GuiguException(201, "删除专辑失败");
        }
        // 删除专辑标签表的数据
        int row = albumAttributeValueMapper.delete(
                new LambdaQueryWrapper<AlbumAttributeValue>()
                        .eq(AlbumAttributeValue::getAlbumId, albumId));
        if(row < 0){
            throw new GuiguException(201, "删除专辑失败");
        }
        // 删除专辑统计表的数据
        row = albumStatMapper.delete(
                new LambdaQueryWrapper<AlbumStat>()
                        .eq(AlbumStat::getAlbumId, albumId));
        if(row < 0){
            throw new GuiguException(201, "删除专辑失败");
        }
        // es中删除专辑的数据
        CorrelationData correlationData = new CorrelationData();
        correlationData.setReturned(new ReturnedMessage(
                new Message(albumId.toString().getBytes()),
                -1,
                null,
                null,
                "album.es.down"));
        rabbitTemplate.convertAndSend("album_info_exchange",
                                      "album.es.down",
                                      albumId + "",
                                      correlationData);
        // 1108 删除缓存
        removeAlbumFromRedis(albumId);
    }

    /**
     * 在专辑发生变化的时候, 删除redis中的专辑的缓存
     * @param albumId
     * @return
     */
    @Value("${album.redis.key}")
    private String albumRedisKeys;
    private void removeAlbumFromRedis(Long albumId) {
        // 异步第一次删除
        // 分割键值
        String[] keys = albumRedisKeys.split("&");
        CompletableFuture.runAsync(() -> {
            for (String key : keys) {
                // 删除本专辑相关的缓存数据
                redisTemplate.delete(key + Arrays.asList(albumId));
            }
        }, threadPoolExecutor)
                .whenCompleteAsync((a, b) -> { // 无论如何都会进去执行: finally 最终没有return
            if (b != null){
                // 前面的任务出现异常了
                for (String key : keys) {
                    // 删除本次专辑相关的缓存数据
                    redisTemplate.expire(key + Arrays.asList(albumId), 3, TimeUnit.SECONDS);
                }
            }
        });
        // .handleAsync((a,b)->{//无论如何都会进去执行,最终有个return
        //
        // 				});
        // .exceptionally();只有发生异常才进入执行: catch,,最终有个return

    }

    /**
     * 修改专辑时回显专辑信息
     * @param albumId
     * @return null
     */
    @Override
    public AlbumInfo getAlbumInfo(Long albumId) {
        Long userId = AuthContextHolder.getUserId();
        // 专辑的主要信息
        AlbumInfo albumInfo = this.getOne(new LambdaQueryWrapper<AlbumInfo>()
                                                  .eq(AlbumInfo::getId, albumId)
                                                  .eq(AlbumInfo::getUserId, userId));
        // 非空判断
        if(albumInfo == null){
            throw new GuiguException(201, "专辑不存在!");
        }
        // 专辑的属性信息
        List<AlbumAttributeValue> albumAttributeValueList
                = albumAttributeValueMapper.selectList(new LambdaQueryWrapper<AlbumAttributeValue>()
                .eq(AlbumAttributeValue::getAlbumId, albumId));
        // 赋值
        albumInfo.setAlbumAttributeValueVoList(albumAttributeValueList);
        // 返回
        return albumInfo;
    }

    /**
     * 修改专辑信息
     * @param albumInfoVo
     * @param albumId
     * @return
     */
    @Override
    public void updateAlbumInfo(Long albumId, AlbumInfoVo albumInfoVo) {
        Long userId = AuthContextHolder.getUserId();
        // 1.先从数据库中专辑的数据
        AlbumInfo albumInfoDb = this.getById(albumId);
        // 如果为空 直接结束方法
        if (albumInfoDb == null){
            return;
        }
        // 2.修改专辑数据
        AlbumInfo albumInfo = new AlbumInfo();
        BeanUtils.copyProperties(albumInfoVo, albumInfo);
        albumInfo.setUserId(userId);
        albumInfo.setId(albumId);
        boolean flag = this.saveOrUpdate(albumInfo);
        if (!flag){
            throw new GuiguException(201, "修改专辑数据失败");
        }
        // 3.删除专辑的标签表的数据
        int row = albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>()
                .eq(AlbumAttributeValue::getAlbumId, albumId));
        if (row <= 0){
            throw new GuiguException(201, "删除专辑标签表数据失败");
        }
        // 4.新增专辑的标签表的数据
        // 遍历标签列表 逐条新增
        albumInfoVo.getAlbumAttributeValueVoList().forEach(albumAttributeValueVo -> {
            // 属性转移
            AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
            BeanUtils.copyProperties(albumAttributeValueVo, albumAttributeValue);
            // 设置专辑的Id
            albumAttributeValue.setAlbumId(albumId);
            // 执行新增
            int row2 = albumAttributeValueMapper.insert(albumAttributeValue);
            if (row2 <= 0){
                throw new GuiguException(201,"新增专辑的标签数据失败");
            }
        });

        // 1105 判断专辑的状态是否为上架 上架则通知es同步数据 下架则删除数据
        CorrelationData correlationData = new CorrelationData();
        if(albumInfo.getIsOpen().equals("1")){
            correlationData.setReturned(new ReturnedMessage(
                    new Message(albumId.toString().getBytes()),
                    -1,
                    null,
                    null,
                    "album.es.upper"));
            //上架: es写数据
            rabbitTemplate.convertAndSend("album_info_exchange",
                                          "album.es.upper",
                                          albumId + "",
                                          correlationData);
        }else{
            correlationData.setReturned(new ReturnedMessage(
                    new Message(albumId.toString().getBytes()),
                    -1,
                    null,
                    null,
                    "album.es.down"));
            //下架: es删除数据
            rabbitTemplate.convertAndSend("album_info_exchange",
                                          "album.es.down",
                                          albumId + "",
                                          correlationData);
        }
        // 1108 删除专辑在redis中的数据
        removeAlbumFromRedis(albumId);
    }

    @Override
    public Object findUserAllAlbumList() {
        Long userId = AuthContextHolder.getUserId();
        Page<AlbumInfo> page = this.page(new Page<>(1, 10), new LambdaQueryWrapper<AlbumInfo>() // 默认查看第一页
                .eq(AlbumInfo::getUserId, userId)
                .eq(AlbumInfo::getStatus, SystemConstant.ALBUM_STATUS_PASS)// 审核通过的
                .orderByDesc(BaseEntity::getId));
        return page.getRecords();
    }

    /**
     * 查询专辑的统计信息
     * @param albumId
     * @return
     */


    @Override
    public Map<String, String>  getAlbumStat(Long albumId) {

        // 查询专辑的统计列表
        List<AlbumStat> albumStatList = albumStatMapper.selectList(new LambdaQueryWrapper<AlbumStat>()
                                                                        .eq(AlbumStat::getAlbumId, albumId)
                                                                        .select(AlbumStat::getStatType, AlbumStat::getStatNum));
        // 将集合转成Map<StatType, StatNum>
        return albumStatList.stream().collect(Collectors.toMap(
                key -> key.getStatType(),
                val -> val.getStatNum().toString()
        ));
    }

    /**
     * 查询专辑的标签数据
     * @param albumId
     * @return
     */
    @Override
    public List<AlbumAttributeValue> getAlbumAttributeValue(Long albumId) {
        List<AlbumAttributeValue> albumAttributeValueList = albumAttributeValueMapper.selectList(new LambdaQueryWrapper<AlbumAttributeValue>()
                                                                                                         .eq(AlbumAttributeValue::getAlbumId, albumId));
        return albumAttributeValueList;
    }



  /**
     * 初始化专辑的统计表数据
     * @param albumInfoId
     * @return null
     */
    private void initAlbumStat(Long albumInfoId) {
        // 初始化
        AlbumStat albumStat = new AlbumStat();
        albumStat.setStatNum(0);
        albumStat.setAlbumId(albumInfoId);
        // 0401-播放量
        albumStat.setStatType(SystemConstant.ALBUM_STAT_PLAY);
        albumStatMapper.insert(albumStat);
        // 0402-订阅量
        albumStat.setId(null); // 将对象的Id设置为空 即为新增
        albumStat.setStatType(SystemConstant.ALBUM_STAT_SUBSCRIBE);
        albumStatMapper.insert(albumStat);
        // 0403-购买量
        albumStat.setId(null);
        albumStat.setStatType(SystemConstant.ALBUM_STAT_BROWSE);
        albumStatMapper.insert(albumStat);
        // 0404-评论数
        albumStat.setId(null);
        albumStat.setStatType(SystemConstant.ALBUM_STAT_COMMENT);
        albumStatMapper.insert(albumStat);
    }
}
